#!/usr/bin/env node
/**
 * 课程API报告工具
 * 包含公钥注册和上报功能
 */

import fs from 'fs/promises';
import path from 'path';
import os from 'os';
import crypto from 'crypto';
import axios from 'axios';
import inquirer from 'inquirer';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';

import { runAllTests, fetchTodos } from './api-tests.js';


// 加载.env文件
dotenv.config();

// 基础配置
const CONFIG_DIR = path.join(os.homedir(), '.course-reporter');
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
const DEFAULT_CONFIG = {
  apiUrl: process.env.API_URL || 'http://localhost:8080/api',
  studentId: '',
  name: '',
  autoReportInterval: 15 * 60 * 1000,
  keyPair: null
};

// 初始化配置目录
async function initConfigDir() {
  try {
    await fs.mkdir(CONFIG_DIR, { recursive: true });
  } catch (error) {
    console.error('创建配置目录失败:', error.message);
    throw error;
  }
}

// 加载配置
async function loadConfig() {
  try {
    await initConfigDir();
    
    try {
      const data = await fs.readFile(CONFIG_FILE, 'utf8');
      const config = JSON.parse(data);
      return { ...DEFAULT_CONFIG, ...config };
    } catch (error) {
      // 如果配置文件不存在或格式不正确，返回默认配置
      if (error.code === 'ENOENT' || error instanceof SyntaxError) {
        console.log('未找到配置文件，使用默认配置');
        return { ...DEFAULT_CONFIG };
      }
      throw error;
    }
  } catch (error) {
    console.error('加载配置失败:', error.message);
    return { ...DEFAULT_CONFIG };
  }
}

// 保存配置
async function saveConfig(config) {
  try {
    await initConfigDir();
    const fullConfig = { ...DEFAULT_CONFIG, ...config };
    await fs.writeFile(CONFIG_FILE, JSON.stringify(fullConfig, null, 2));
    return true;
  } catch (error) {
    console.error('保存配置失败:', error.message);
    return false;
  }
}

// 获取密钥路径
function getKeyPaths() {
  return {
    publicKeyPath: path.join(CONFIG_DIR, 'public_key.pem'),
    privateKeyPath: path.join(CONFIG_DIR, 'private_key.pem')
  };
}

// 生成RSA密钥对并保存
async function generateAndSaveKeyPair(config) {
  try {
    console.log('正在生成RSA密钥对...');
    
    // 创建RSA密钥对
    const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
      modulusLength: 2048,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem'
      }
    });
    
    // 获取密钥保存路径
    const { publicKeyPath, privateKeyPath } = getKeyPaths();
    
    // 保存密钥到文件
    await fs.writeFile(publicKeyPath, publicKey);
    await fs.writeFile(privateKeyPath, privateKey, { mode: 0o600 }); // 更安全的权限
    
    // 更新配置
    const keyPair = {
      name: `${os.hostname()}-${Date.now()}`,
      created: new Date().toISOString(),
      publicKeyFile: publicKeyPath,
      privateKeyFile: privateKeyPath
    };
    
    config.keyPair = keyPair;
    await saveConfig(config);
    
    console.log('密钥对已生成并保存');
    
    return config;
  } catch (error) {
    console.error('生成密钥对失败:', error.message);
    throw error;
  }
}

// 向服务器注册公钥
async function registerPublicKey(config) {
  try {
    console.log('向服务器注册公钥...');
    
    // 确保有密钥对
    if (!config.keyPair) {
      throw new Error('未找到密钥对，无法注册公钥');
    }
    
    // 从文件读取公钥
    const publicKeyPath = config.keyPair.publicKeyFile;
    let publicKey;
    try {
      publicKey = await fs.readFile(publicKeyPath, 'utf8');
    } catch (error) {
      throw new Error(`无法读取公钥文件: ${error.message}`);
    }
    
    // 设置请求头
    const headers = {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.STUDENT_API_KEY || 'testkey',
      'X-Student-ID': config.studentId
    };
    
    // 获取挑战码
    let challenge = '';
    let signature = '';
    try {
      console.log('获取认证挑战码...');
      const challengeRes = await axios.get(
        `${config.apiUrl}/students/auth/challenge/${config.studentId}`,
        { headers }
      );
      
      challenge = challengeRes.data.challenge;
      
      if (challenge) {
        // 使用私钥签名挑战码
        console.log('使用私钥签名挑战码...');
        const privateKeyPath = config.keyPair.privateKeyFile;
        try {
          const privateKey = await fs.readFile(privateKeyPath, 'utf8');
          const sign = crypto.createSign('SHA256');
          sign.update(challenge);
          sign.end();
          signature = sign.sign(privateKey, 'base64');
        } catch (error) {
          console.warn('无法签名挑战码:', error.message);
        }
      }
    } catch (error) {
      console.warn('获取挑战码失败，尝试直接注册:', error.message);
    }
    
    // 准备注册数据
    const registrationData = {
      publicKey,
      keyName: config.keyPair.name || `${os.hostname()}-${Date.now()}`,
      signature,
      challenge
    };
    
    console.log('注册数据准备完成，包含以下字段:', Object.keys(registrationData));
    
    try {
      // 向服务器发送注册请求
      const response = await axios.post(
        `${config.apiUrl}/students/auth/register-key/${config.studentId}`,
        registrationData,
        { headers }
      );
      
      console.log('公钥注册成功:', response.data.message || '服务器接受了密钥');
      
      // 更新配置中的密钥信息（如果服务器返回了keyId）
      if (response.data.keyId) {
        config.keyPair.keyId = response.data.keyId;
        await saveConfig(config);
      }
      
      return response.data;
    } catch (error) {
      // 处理不同类型的错误
      if (error.response?.status === 409) {
        // 409 Conflict - 服务器已有此学生的密钥
        console.warn('公钥注册失败: 服务器已有此学生的密钥记录');
        console.warn('如果您更换了环境，请联系教师重置您的公钥');
        return { keyExists: true, message: '服务器已有密钥记录' };
      } else if (error.response?.status === 401) {
        console.warn('公钥注册失败: 认证失败，请检查学号和API密钥');
      } else {
        console.error('公钥注册失败:', error.message);
        if (error.response) {
          console.error('服务器错误:', error.response.data);
        }
      }
      throw error;
    }
  } catch (error) {
    console.error('注册公钥失败:', error.message);
    throw error;
  }
}

// 认证过程
async function authenticate(config) {
  try {
    console.log('正在进行认证...');
    
    // 检查是否有密钥对
    if (!config.keyPair) {
      throw new Error('未找到密钥对，请先运行 setup 命令');
    }
    
    // 获取密钥文件路径
    const { privateKeyFile } = config.keyPair;
    
    // 读取私钥
    let privateKey;
    try {
      privateKey = await fs.readFile(privateKeyFile, 'utf8');
    } catch (error) {
      throw new Error('密钥文件不存在或无法读取: ' + error.message);
    }
    
    // 获取挑战码
    console.log('获取挑战码...');
    const challengeResponse = await axios.get(
      `${config.apiUrl}/students/auth/challenge/${config.studentId}`
    );
    
    console.log('服务器响应状态:', challengeResponse.status);
    
    // 确保有挑战码
    const { challenge } = challengeResponse.data;
    if (!challenge) {
      console.error('警告: 挑战码为空或未定义');
      console.error('服务器响应:', JSON.stringify(challengeResponse.data, null, 2));
      throw new Error('服务器未返回有效的挑战码');
    }
    
    console.log('收到挑战码:', challenge);
    
    // 使用私钥签名挑战码
    console.log('正在签名挑战码...');
    const sign = crypto.createSign('SHA256');
    sign.update(challenge);
    sign.end();
    const signature = sign.sign(privateKey, 'base64');
    
    console.log('挑战码签名完成');
    
    // 验证签名
    try {
      console.log('验证签名...');
      const verifyResponse = await axios.post(
        `${config.apiUrl}/students/auth/verify/${config.studentId}`,
        { signature, challenge }
      );
      console.log('签名验证成功:', verifyResponse.data.message || '验证通过');
    } catch (verifyError) {
      // 检查错误类型并做出相应处理
      if (verifyError.response) {
        const errorData = verifyError.response.data;
        
        // 情况1: 需要重新注册密钥（教师已重置密钥）
        if (errorData && errorData.requiresReregistration) {
          console.log('服务器已重置密钥，需要重新生成和注册密钥...');
          throw new Error('服务器已重置密钥，请重新运行 setup 命令生成和注册密钥');
        } 
        
        // 情况2: 服务器没有该学生的公钥记录
        else if (errorData && errorData.error && 
                (errorData.error.includes('没有注册公钥') || 
                  errorData.error.includes('未找到公钥'))) {
          console.error('服务器端没有找到公钥记录');
          throw new Error('未在服务器上注册公钥，请先运行 setup 命令注册公钥');
        } 
        
        // 情况3: 公钥不匹配（可能是学生更换了环境）
        else if (errorData && errorData.error && 
                (errorData.error.includes('验证失败') || 
                  errorData.error.includes('签名无效'))) {
          console.error('签名验证失败，可能是您更换了环境或密钥被篡改');
          throw new Error('签名验证失败，如果您更换了环境，请联系教师重置您的公钥，然后重新运行 setup 命令');
        }
      }
      
      // 其他错误
      console.error('签名验证失败:', verifyError.message);
      if (verifyError.response && verifyError.response.data) {
        console.error('服务器错误详情:', verifyError.response.data);
      }
      throw verifyError;
    }
    
    return {
      challenge,
      signature
    };
  } catch (error) {
    console.error('认证失败:', error.message);
    throw error;
  }
}

// 收集硬件信息
async function collectHardwareInfo() {
  try {
    // 基础系统信息
    const platform = os.platform();
    const hostname = os.hostname();
    const username = os.userInfo().username;
    const totalMemory = os.totalmem();
    
    // CPU信息
    const cpuModel = os.cpus()[0]?.model || 'unknown';
    const cpuCores = os.cpus().length;
    
    // 网络接口
    const networkInterfaces = os.networkInterfaces();
    const macAddresses = [];
    
    // 提取MAC地址
    Object.keys(networkInterfaces).forEach(ifName => {
      networkInterfaces[ifName].forEach(iface => {
        if ((iface.family === 'IPv4' || iface.family === 4) && !iface.internal) {
          macAddresses.push(iface.mac);
        }
      });
    });
    
    // 组合硬件信息
    return {
      cpuModel,
      cpuCores,
      totalMemory,
      platform,
      hostname,
      username,
      macAddresses,
      deviceId: `${hostname}-${macAddresses[0] || 'unknown'}`,
      timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
      userAgent: `Node.js ${process.version} (${platform})`
    };
  } catch (error) {
    console.error('收集硬件信息失败:', error.message);
    // 返回基本信息
    return {
      platform: os.platform(),
      hostname: os.hostname(),
      username: os.userInfo().username,
      totalMemory: os.totalmem(),
      cpuModel: 'unknown',
      cpuCores: os.cpus().length,
      macAddresses: []
    };
  }
}

// 获取IP地址
async function getIPAddress() {
  // 获取所有网络接口
  const interfaces = os.networkInterfaces();
  
  // 尝试找到一个非本地的IPv4地址
  for (const name of Object.keys(interfaces)) {
    for (const iface of interfaces[name]) {
      // 跳过内部/本地地址，兼容不同版本的Node.js
      if ((iface.family === 'IPv4' || iface.family === 4) && !iface.internal) {
        return iface.address;
      }
    }
  }
  
  // 如果没有找到，返回localhost
  return '127.0.0.1';
}

// 尝试连接实际的Todo API
async function fetchActualTodos() {
  try {
    console.log('尝试从Todo API获取数据...');
    
    // 假设学生的API运行在本地3000端口
    const todoApiUrl = 'http://localhost:3000/todos';
    
    const response = await axios.get(todoApiUrl, { timeout: 3000 });
    
    if (Array.isArray(response.data)) {
      console.log(`成功从实际API获取 ${response.data.length} 个待办事项`);
      return response.data;
    } else {
      console.warn('API返回了非数组数据');
      return [];
    }
  } catch (error) {
    console.warn('无法从实际API获取数据:', error.message);
    return [];
  }
}

// 模拟运行API测试
async function runAPIMockTests() {
  console.log('执行API测试...');
  
  try {
    // 尝试使用独立测试模块运行所有测试
    const testResults = await runAllTests();
    return testResults;
  } catch (error) {
    console.error('运行API测试失败:', error.message);
    console.log('使用模拟数据作为替代，但会明确标识错误...');
    
    // 保存原始错误信息以便提交给教师
    const errorMessage = `API测试执行失败: ${error.message}`;
    
    // 返回模拟的测试结果，但明确标识为错误情况
    return {
      totalPassed: 0,
      totalFailed: 2,
      score: 0,
      maxPossibleScore: 20,
      timestamp: new Date().toISOString(),
      isMockData: true, // 明确标识这是模拟数据
      errorReason: errorMessage, // 提供详细错误原因
      tests: [
        {
          name: "GET /todos 获取所有待办事项",
          passed: false,
          response: null,
          error: "无法连接到学生API或执行测试: " + error.message,
          mockError: true, // 标识这是模拟的错误
          score: { value: 0, maxValue: 10, comments: errorMessage }
        },
        {
          name: "POST /todos 创建待办事项",
          passed: false,
          response: null,
          error: "无法连接到学生API或执行测试: " + error.message,
          mockError: true, // 标识这是模拟的错误
          score: { value: 0, maxValue: 10, comments: errorMessage }
        }
      ]
    };
  }
}


// 创建报告数据
async function createReportData(config, authData) {
  try {
    console.log('收集系统信息...');
    
    // 获取硬件信息
    const hardwareInfo = await collectHardwareInfo();
    
    // 获取实际待办事项或使用模拟数据
    let todos = [];
    try {
      // 使用独立测试模块获取待办事项
      todos = await fetchTodos();
    } catch (error) {
      // 使用模拟数据
      todos = [
        { id: 1, title: "完成作业", completed: false },
        { id: 2, title: "阅读文章", completed: true }
      ];
    }
    
    // 执行测试
    const testResults = await runAPIMockTests();
    
    // 创建报告数据
    const reportData = {
      studentId: config.studentId,
      name: config.name || os.userInfo().username,
      apiVersion: '1.0.0',
      ipAddress: await getIPAddress(),
      port: 3000,
      timestamp: new Date().toISOString(),
      signature: authData.signature,
      challenge: authData.challenge, 
      hardwareInfo,
      data: {
        todoCount: todos.length,
        todos,
        testResults
      }
    };
    
    return reportData;
  } catch (error) {
    console.error('创建报告数据失败:', error.message);
    throw error;
  }
}

// 发送报告
async function sendReport(config, reportData) {
  try {
    console.log('发送API状态报告...');
    
    // 设置请求头
    const headers = {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.STUDENT_API_KEY || 'testkey',
      'X-Student-ID': config.studentId
    };
    
    // 发送报告
    console.log('发送报告到服务器...');
    try {
      const response = await axios.post(
        `${config.apiUrl}/students/report`,
        reportData,
        { headers }
      );
      
      console.log('报告发送成功:', response.data.message || '服务器已接收报告');
      
      // 检查是否有待处理的命令
      if (response.data.command) {
        console.log(`服务器发送命令: ${response.data.command}`);
      }
      
      return response.data;
    } catch (error) {
      if (error.response && error.response.data) {
        // 检查具体错误类型
        const errorMsg = error.response.data.error || '未知错误';
        console.error('服务器响应错误:', error.response.data);
        throw new Error(errorMsg);
      } else {
        console.error('发送报告失败:', error.message);
        throw error;
      }
    }
  } catch (error) {
    console.error('报告发送失败:', error.message);
    throw error;
  }
}

// 设置配置
async function setupConfig() {
  try {
    console.log('===== 课程API报告工具配置 =====');
    
    // 加载现有配置
    const config = await loadConfig();
    
    // 提示用户输入配置
    const answers = await inquirer.prompt([
      {
        type: 'input',
        name: 'apiUrl',
        message: '请输入汇报API服务器地址:',
        default: config.apiUrl || process.env.API_URL || 'http://localhost:8080/api'
      },
      {
        type: 'input',
        name: 'studentId',
        message: '请输入你的学号:',
        default: config.studentId,
        validate: input => input.trim() !== '' || '学号不能为空'
      },
      {
        type: 'input',
        name: 'name',
        message: '请输入你的姓名:',
        default: config.name,
        validate: input => input.trim() !== '' || '姓名不能为空'
      }
    ]);
    
    // 更新配置
    const newConfig = { ...config, ...answers };
    
    // 处理密钥对
    if (!newConfig.keyPair) {
      console.log('正在生成密钥对以进行安全认证...');
      await generateAndSaveKeyPair(newConfig);
    }
    
    // 保存配置
    await saveConfig(newConfig);
    console.log('配置已保存');
    
    // 向服务器注册密钥
    console.log('正在向服务器注册公钥...');
    try {
      await registerPublicKey(newConfig);
      console.log('公钥注册成功！');
    } catch (error) {
      if (error.response?.data?.keyExists) {
        console.log('服务器已有您的公钥记录。如果您更换了环境，请联系教师重置您的公钥。');
      } else {
        console.error('公钥注册失败:', error.message);
      }
    }
    
    // 提示完成报告
    if (newConfig.studentId) {
      const { report } = await inquirer.prompt([
        {
          type: 'confirm',
          name: 'report',
          message: '是否立即进行一次状态报告?',
          default: true
        }
      ]);
      
      if (report) {
        await reportOnce();
      }
    }
    
  } catch (error) {
    console.error('配置过程中出错:', error.message);
  }
}

// 单次报告
async function reportOnce() {
  try {
    // 加载配置
    const config = await loadConfig();
    
    if (!config.studentId) {
      console.log('请先设置学号，运行 setup 命令配置基本信息');
      return { success: false, error: '学号未设置' };
    }
    
    console.log(`===== 开始报告 (${config.studentId}) =====`);
    
    // 检查是否有密钥对
    if (!config.keyPair) {
      console.log('未找到密钥对，请先运行 setup 命令生成密钥');
      return { success: false, error: '密钥对不存在' };
    }
    
    // 收集系统信息并准备报告数据
    console.log('收集系统信息...');
    const hardwareInfo = await collectHardwareInfo();
    
    // 获取待办事项
    let todos = [];
    try {
      todos = await fetchTodos();
    } catch (error) {
      console.warn('获取待办事项失败，使用空列表:', error.message);
    }
    
    // 执行测试
    const testResults = await runAPIMockTests();
    
    // 设置请求头
    const headers = {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.STUDENT_API_KEY || 'testkey',
      'X-Student-ID': config.studentId
    };
    
    // 准备初始报告数据（没有签名）
    let reportData = {
      studentId: config.studentId,
      name: config.name || os.userInfo().username,
      apiVersion: '1.0.0',
      ipAddress: await getIPAddress(),
      port: 3000,
      timestamp: new Date().toISOString(),
      hardwareInfo,
      data: {
        todoCount: todos.length,
        todos,
        testResults
      }
    };
    
    // 如果配置中有公钥信息，添加到硬件信息中
    if (config.keyPair && config.keyPair.publicKeyFile) {
      try {
        const publicKey = await fs.readFile(config.keyPair.publicKeyFile, 'utf8');
        reportData.hardwareInfo.publicKey = publicKey;
      } catch (error) {
        console.warn('无法读取公钥:', error.message);
      }
    }
    
    try {
      // 尝试发送报告
      console.log('发送报告...');
      const response = await axios.post(
        `${config.apiUrl}/students/report`,
        reportData,
        { headers }
      );
      
      console.log('报告发送成功:', response.data.message || '服务器已接收报告');
      return response.data;
    } catch (error) {
      // 检查是否需要签名验证
      if (error.response?.status === 401) {
        const errorData = error.response.data;
        
        // 检查是否是需要重新注册
        if (errorData.requiresReregistration) {
          console.log('服务器指示需要重新注册公钥（教师可能已重置您的密钥）');
          console.log('请重新运行 setup 命令重新生成和注册密钥');
          return { success: false, error: '需要重新注册公钥' };
        }
        
        // 检查是否需要签名认证
        if (errorData.requiresAuth && errorData.challenge) {
          console.log('服务器要求签名验证，正在处理...');
          
          try {
            // 读取私钥
            const privateKeyPath = config.keyPair.privateKeyFile;
            const privateKey = await fs.readFile(privateKeyPath, 'utf8');
            
            // 使用私钥签名挑战码
            const sign = crypto.createSign('SHA256');
            sign.update(errorData.challenge);
            sign.end();
            const signature = sign.sign(privateKey, 'base64');
            
            console.log('挑战码签名完成，重新提交报告...');
            
            // 添加签名到报告数据
            reportData.signature = signature;
            
            // 重新提交报告
            const retryResponse = await axios.post(
              `${config.apiUrl}/students/report`,
              reportData,
              { headers }
            );
            
            console.log('报告发送成功:', retryResponse.data.message || '服务器已接收报告');
            return retryResponse.data;
          } catch (signError) {
            console.error('签名验证失败:', signError.message);
            console.log('如果您更换了环境，请联系教师重置您的密钥，然后重新运行 setup 命令');
            return { success: false, error: '签名验证失败' };
          }
        }
        
        // 其他认证错误
        console.error('认证失败:', errorData.error || '未知错误');
        if (errorData.error && errorData.error.includes('未预先注册')) {
          console.log('您的学号未在系统中注册，请联系教师添加您的学生信息');
        }
        
        return { success: false, error: errorData.error || '认证失败' };
      }
      
      // 其他错误
      console.error('报告发送失败:', error.message);
      if (error.response?.data) {
        console.error('服务器错误:', error.response.data);
      }
      
      return { success: false, error: '报告发送失败' };
    }
  } catch (error) {
    console.error('报告过程出错:', error.message);
    return { success: false, error: error.message };
  }
}
    
// 显示状态信息
async function showStatus() {
  try {
      // 加载配置
      const config = await loadConfig();
      
      console.log('===== 当前配置状态 =====');
      console.log('API服务器:', config.apiUrl);
      console.log('学号:', config.studentId || '未设置');
      console.log('姓名:', config.name || '未设置');
      
      if (config.keyPair) {
      console.log('\n密钥信息:');
      console.log('设备名称:', config.keyPair.name);
      console.log('创建时间:', config.keyPair.created);
      console.log('公钥文件:', config.keyPair.publicKeyFile);
      console.log('私钥文件:', config.keyPair.privateKeyFile);
      
      // 检查文件是否存在
      try {
          await fs.access(config.keyPair.publicKeyFile);
          await fs.access(config.keyPair.privateKeyFile);
          console.log('密钥文件状态: 正常');
      } catch (error) {
          console.log('密钥文件状态: 异常 (文件不存在或无法访问)');
      }
      } else {
      console.log('\n未配置密钥对，请运行 setup 命令进行配置');
      }
      
      // 检查API连接
      try {
      const apiUrl = new URL(`/students/auth/challenge/${config.studentId}`, config.apiUrl);
      console.log('\n正在检查API服务器连接...');
      await axios.get(apiUrl.toString(), { timeout: 5000 });
      console.log('API服务器连接: 正常');
      } catch (error) {
      console.log('API服务器连接: 异常');
      console.log('错误详情:', error.message);
      }
      
      // 检查本地API可用性
      try {
      console.log('\n正在检查本地Todo API可用性...');
      await axios.get('http://localhost:3000/todos', { timeout: 3000 });
      console.log('本地Todo API: 可用');
      } catch (error) {
      console.log('本地Todo API: 不可用');
      console.log('错误详情:', error.message);
      }
  } catch (error) {
      console.error('获取状态失败:', error.message);
  }
}

// 帮助信息
function showHelp() {
console.log(`
课程API状态报告简化版工具

使用方法:
setup   - 设置报告器配置并注册公钥
report  - 单次报告API状态
status  - 显示当前配置和连接状态
help    - 显示此帮助信息

示例:
node simple-reporter.js setup
node simple-reporter.js report
node simple-reporter.js status
`);
}

// 主函数
async function main() {
const command = process.argv[2];

switch (command) {
    case 'setup':
    await setupConfig();
    break;
    case 'report':
    await reportOnce();
    break;
    case 'status':
    await showStatus();
    break;
    case 'help':
    default:
    showHelp();
    break;
}
}

// 运行主函数
main().catch(error => {
console.error('程序执行失败:', error);
process.exit(1);
});